package com.tiger.log.core.processing.auth;

import com.tiger.log.common.annotation.auth.Keyword;
import com.tiger.log.common.annotation.auth.LoginCollect;
import com.tiger.log.common.annotation.auth.LogoutCollect;
import com.tiger.log.common.constant.EnableProperties;
import com.tiger.log.common.constant.LogConstant;
import com.tiger.log.common.constant.TokenProperties;
import com.tiger.log.common.entity.SysAuthLog;
import com.tiger.log.common.enums.AuthType;
import com.tiger.log.common.enums.Result;
import com.tiger.log.common.exception.member.EnumsNotMatchException;
import com.tiger.log.common.util.MeUtil;
import com.tiger.log.core.parse.ProceedParse;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

/**
 * @ClassName LogoutProcessing
 * @Description TODO
 * @Author huxuehao
 **/
@Component
public class AuthProcessing {

    private final ProceedParse proceedParse;
    private final TokenProperties tokenProperties;
    private final EnableProperties enableProperties;

    public AuthProcessing(ProceedParse proceedParse, TokenProperties tokenProperties, EnableProperties enableProperties) {
        this.proceedParse = proceedParse;
        this.tokenProperties = tokenProperties;
        this.enableProperties = enableProperties;
    }

    /**
     * 验证是否非法
     */
    public boolean isIllegal(ProceedingJoinPoint joinPoint, AuthType authType) {
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        String code;
        switch (authType) {
            case LOGIN:
                code = method.getAnnotation(LoginCollect.class).code();
                return !(enableProperties.isOpen() || enableProperties.getExcludeCodes().contains(code));
            case LOGOUT:
                code = method.getAnnotation(LogoutCollect.class).code();
                return !(enableProperties.isOpen() || enableProperties.getExcludeCodes().contains(code));
            default:
                throw new EnumsNotMatchException("AuthType匹配失败");
        }
    }

    /**
     * 前置处理
     */
    public void proceedPreProcessing(SysAuthLog authLog, ProceedingJoinPoint joinPoint, AuthType authType) {
        fillRecordCollect(authLog, joinPoint, authType);
        fillRecordRequest(authLog, joinPoint, authType);
    }

    /**
     * 后置处理
     */
    public void proceedPostProcessing(SysAuthLog authLog, Object res, boolean isCatch) {
        fillRecordResult(authLog, res, isCatch);
    }

    private void fillRecordCollect(SysAuthLog authLog, ProceedingJoinPoint joinPoint, AuthType authType) {
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        switch (authType) {
            case LOGIN:
                authLog.setComment(method.getAnnotation(LoginCollect.class).comment());
                break;
            case LOGOUT:
                authLog.setComment(method.getAnnotation(LogoutCollect.class).comment());
                break;
            default:
                throw new EnumsNotMatchException("AuthType匹配失败");
        }
        authLog.setOperationType(authType.toString());
    }

    private void fillRecordRequest(SysAuthLog authLog, ProceedingJoinPoint joinPoint,  AuthType authType) {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert requestAttributes != null;
        HttpServletRequest request = requestAttributes.getRequest();

        authLog.setRequestAddress(request.getRemoteAddr());
        authLog.setRequestUri(request.getRequestURI());
        authLog.setRequestTime(MeUtil.currentDatetime(LogConstant.TIME_FORMAT));
        authLog.setUserAgent(request.getHeader("User-Agent"));
        switch (authType) {
            case LOGIN:
                authLog.setUserCode(proceedParse.userCodeByKeywordParse(getKeyWord(joinPoint)));
                break;
            case LOGOUT:
                authLog.setUserCode(proceedParse.userCodeByTokenParse(request.getHeader(tokenProperties.getTokenKey())));
                break;
            default:
                throw new EnumsNotMatchException("AuthType匹配失败");
        }
    }

    /**
     * 获取KeyWord
     */
    private Object getKeyWord(ProceedingJoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        /* 获取参数 */
        Parameter[] parameters = signature.getMethod().getParameters();
        for (int i = 0; i <parameters.length; i++) {
            if ( parameters[i].isAnnotationPresent(Keyword.class)) {
                /* 获取参数值 */
                return joinPoint.getArgs()[i];
            }
        }
        throw new RuntimeException("在参数中没有找到@Keyword注解");
    }

    private void fillRecordResult(SysAuthLog authLog, Object res, boolean isCatch) {
        if (res == null && isCatch) {
            authLog.setOperationResult(Result.FAIL.toString());
        } else {
            authLog.setOperationResult(proceedParse.executeResultParse(res).toString());
        }
    }
}
